//
//  HLIdleOperationQueue.m
//  HLDesktop
//
//  Created by 黄龙 on 2023/11/27.
//

#import "HLIdleOperationQueue.h"

//beforWaiting的回调
void MyOperationRunLoopObserverWaitingCallBack (CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);


//操作类，只做赋值和回调
@interface HLIdleOperation ()
@property (nonatomic, copy) void(^executeOperation)(HLIdleOperation *operation);
//执行函数
- (void)execute;

@end

@implementation HLIdleOperation

- (void)execute
{
    if (self.executeOperation) {
        self.executeOperation(self);
    }
}
@end



typedef NS_ENUM(NSInteger, HLIdleOperationQueueState) {
    MyOperationQueueState_None,
    MyOperationQueueState_Start,
    MyOperationQueueState_Executing,
    MyOperationQueueState_lastExecuteFinish,
    MyOperationQueueState_AllFinish,
};

 @interface HLIdleOperationQueue() {
    CFRunLoopObserverRef runLoopObserver;
}


@property (nonatomic, assign) HLIdleOperationQueueState state;
@property (nonatomic, strong) NSMutableArray<HLIdleOperation *> *queue;
@property (nonatomic, assign) CFAbsoluteTime lastTime;
@end

@implementation HLIdleOperationQueue

+ (instancetype)sharedObject
{
    static dispatch_once_t onceToken;
    static HLIdleOperationQueue *shareObject;
    dispatch_once(&onceToken, ^{
        shareObject = [[HLIdleOperationQueue alloc] init];
    });
    return shareObject;
}

- (void)dealloc
{
    [self removeRunloopCallback];
}

//释放
- (void)removeRunloopCallback
{
    self.state = MyOperationQueueState_None;
    if (runLoopObserver) {
        CFRunLoopRemoveObserver(CFRunLoopGetMain(), runLoopObserver, kCFRunLoopDefaultMode);
        CFRelease(runLoopObserver);
    }
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        _queue = [NSMutableArray new];
        _lastTime = CFAbsoluteTimeGetCurrent() * 1000.0;//乘以1000，变成单位毫秒
        _interval = 30;//30ms，1000ms=1s
        [self initRunloopCallback];
    }
    return self;
}

- (void)initRunloopCallback
{
    //创建上下文
    CFRunLoopObserverContext context = {0, (__bridge void *)self, NULL, NULL, NULL};
    //创建监听和回调
    runLoopObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, YES, 0, &MyOperationRunLoopObserverWaitingCallBack, &context);
//    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
//        kCFRunLoopEntry         = (1UL << 0), // 即将进入Loop
//        kCFRunLoopBeforeTimers  = (1UL << 1), // 即将处理 Timer
//        kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
//        kCFRunLoopBeforeWaiting = (1UL << 5),
        // 即将进入休眠（如果UI为空闲状态，会不断回调此信息60次/s=FPS，如果UI在滑动Scrollview之类的，则会停止;
        //如果UI上有timer在工作,比如1s/次，则每s结束时回调若干次(8次左右)此消息，由此可以看到timer的精确其实不高）
//        kCFRunLoopAfterWaiting  = (1UL << 6), // 刚从休眠中唤醒,如在空闲状态，点击一下UI，就会触发一下回调
//        kCFRunLoopExit          = (1UL << 7), // 即将退出Loop
//    };
    
    //添加监听，主线程CFRunLoopGetMain()回调
    CFRunLoopAddObserver(CFRunLoopGetMain(), runLoopObserver, kCFRunLoopDefaultMode);
//kCFRunLoopDefaultMode(App平时所处的状态，通常主线程就在此mode下运行)
//UITrackingRunLoopMode(UI跟踪mode，追踪诸如ScrollView等的触摸滑动，保证滑动不受其他mode影响)
//kCFRunLoopCommonModes（这是一个占位Mode，没有实际作用，只是同时添加了上面2种模式）
    
}

//执行函数
- (void)executeOperation
{
    switch (self.state) {
        case MyOperationQueueState_None:
        case MyOperationQueueState_Executing:
        case MyOperationQueueState_AllFinish:
//            NSLog(@"MyOperationQueueState_AllFinish");
            return;
        default:
            break;
    }
    CFAbsoluteTime curTime = CFAbsoluteTimeGetCurrent() * 1000;
    if (curTime - _lastTime < _interval) {//30ms内不执行下一个任务
        return;
    }
    _lastTime = curTime;

    @synchronized(self.queue) { //@synchronized (递归互斥锁)
        HLIdleOperation *operation = self.queue.firstObject;//取第一个去执行
        if (operation) {
            self.state = MyOperationQueueState_Executing;
            NSLog(@"executeOperation 执行任务:%p",operation);
            [operation execute];
        }
    }
}

//设置状态为开始
- (void)start
{
   switch (_state) {
       case MyOperationQueueState_Start:
       case MyOperationQueueState_Executing:
           return;
       default:
           break;
   }
   self.state = MyOperationQueueState_Start;
}

//完成了一个任务
- (void)onOperationFinish:(HLIdleOperation *)operation
{
   self.state = MyOperationQueueState_lastExecuteFinish;
   @synchronized(self.queue) {
       [self.queue removeObject:operation];
       if ([self.queue count] == 0) {
           self.state = MyOperationQueueState_AllFinish;
       }
   }
}

#pragma mark - public method
- (void)addBeforeWaitingQueue:(dispatch_block_t )taskBlock
{
    HLIdleOperation *task = [[HLIdleOperation alloc] init];
   task.executeOperation = ^(HLIdleOperation *operation) {
       taskBlock();
       //设置该任务完成
       [[HLIdleOperationQueue sharedObject] onOperationFinish:operation];
   };
   @synchronized(self.queue) {
      if (![self.queue containsObject:task]) {
           [self.queue addObject:task];
           NSLog(@"添加任务：%p",task);
       }
   }
   [self start];//开始
}

@end

//runLoop回调
void MyOperationRunLoopObserverWaitingCallBack (CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
    NSLog(@"MyOperationRunLoopObserverWaitingCallBack..");
    HLIdleOperationQueue *opQueue = (__bridge HLIdleOperationQueue *) info;
    if (opQueue) {
        [opQueue executeOperation];//执行函数
    }
}
